package com.gc.widget.oilcan;

import java.util.Iterator;
import java.util.concurrent.Semaphore;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;

/**
 * Javascript bridge to help launch intents and return results. Any callers will
 * need to provide the "magic key" to help protect against intent calls from
 * non-injected code.
 * 
 * @author jsharkey
 */
public class IntentHelper {

	Activity ctxt;
	private Semaphore resultWait = new Semaphore(0);
	private int resultCode = Activity.RESULT_CANCELED;
	private Intent resultData = null;

	public IntentHelper(Context activity) {
		this.ctxt = (Activity)activity;
	}

	/**
	 * Resolve Intent constants, like Intent.ACTION_PICK
	 */
	private String getConstant(String key) {
		try {
			key = (String) Intent.class.getField(key).get(null);
		} catch (Exception e) {
		}
		return key;
	}

	/**
	 * Parse the given JSON string into an Intent. This would be a good place to
	 * add security checks in the future.
	 */
	private Intent parse(String jsonraw) {
		Intent intent = new Intent();

		try {
			JSONObject json = new JSONObject(jsonraw);

			// look for specific known variables, otherwise assume extras
			// {"action":"ACTION_PICK","category":["CATEGORY_DEFAULT"],"type":"image/*"}

			Iterator keys = json.keys();
			while (keys.hasNext()) {
				String key = (String) keys.next();

				if ("action".equals(key)) {
					intent.setAction(getConstant(json.optString(key)));
				} else if ("category".equals(key)) {
					JSONArray categ = json.optJSONArray(key);
					for (int i = 0; i < categ.length(); i++)
						intent.addCategory(getConstant(categ.optString(i)));
				} else if ("type".equals(key)) {
					intent.setType(json.optString(key));
				} else if ("data".equals(key)) {
					intent.setData(Uri.parse(json.optString(key)));
				} else if ("class".equals(key)) {
					intent.setClassName(ctxt, json.optString(key));
				} else {
					// first try parsing extra as number, otherwise fallback to
					// string
					Object obj = json.get(key);
					if (obj instanceof Integer)
						intent.putExtra(getConstant(key), json.optInt(key));
					else if (obj instanceof Double)
						intent.putExtra(getConstant(key), (float) json
								.optDouble(key));
					else
						intent.putExtra(getConstant(key), json.optString(key));
				}

			}

		} catch (Exception e) {
			intent = null;
		}

		return intent;
	}

	/**
	 * Launch the intent described by JSON. Will only launch if magic key
	 * matches for this browser instance.
	 */
	public void startActivity(String trykey, String json) {

		Intent intent = parse(json);
		if (intent == null)
			return;

		try {
			ctxt.startActivity(intent);
		} catch (ActivityNotFoundException e) {
			// Log.e(TAG,
			// "Couldn't find activity to handle the requested intent", e);
			// Toast.makeText(BrowserActivity.this, R.string.browse_nointent,
			// Toast.LENGTH_SHORT).show();
		}

	}

	/**
	 * Launch the intent described by JSON and block until result is returned.
	 * Will package and return the result as a JSON string. Will only launch if
	 * the magic key matches for this browser instance.
	 */
	public String startActivityForResult(String trykey, String json) {

		Intent intent = parse(json);
		if (intent == null)
			return null;
		resultCode = Activity.RESULT_CANCELED;

		// start this intent and wait for result
		synchronized (this) {
			try {
				((Activity) ctxt).startActivityForResult(intent, 1);
				resultWait.acquire();
			} catch (ActivityNotFoundException e) {
				System.err
						.println("Couldn't find activity to handle the requested intent"
								+ e);
				// Toast.makeText(ctxt, R.string.browse_nointent,
				// Toast.LENGTH_SHORT).show();
			} catch (Exception e) {
				System.err.println("Problem while waiting for activity result"
						+ e);
			}
		}

		JSONObject result = new JSONObject();
		result.optInt("resultCode", resultCode);

		// parse our response into json before handing back
		if (resultCode == Activity.RESULT_OK) {
			if (resultData.getExtras() != null) {
				try {
					JSONObject extras = new JSONObject();
					for (String key : resultData.getExtras().keySet())
						extras.put(key, resultData.getExtras().get(key));
					result.put("extras", extras);

				} catch (JSONException e1) {
					System.err.println("Problem while parsing extras" + e1);
				}
			}

			if (resultData.getData() != null) {
				try {
					// assume that we are handling one contentresolver response
					Cursor cur = ((Activity) ctxt).managedQuery(resultData
							.getData(), null, null, null, null);
					cur.moveToFirst();

					JSONObject data = new JSONObject();
					for (int i = 0; i < cur.getColumnCount(); i++)
						data.put(cur.getColumnName(i), cur.getString(i));
					result.put("data", data);

				} catch (Exception e) {
					System.err.println("Problem while parsing data result" + e);
				}
			}
		}

		String resultraw = result.toString();
		// Log.d(TAG, String.format("startActivityForResult() result=%s",
		// resultraw));
		return resultraw;

	}

}
